package com.z.system.aspect;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Enumeration;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSONObject;
import com.z.system.model.Log;
import com.z.system.model.User;
import com.z.system.service.LogService;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;


/**
 * 日志AOP切面类，用于记录接口请求日志
 * 可以记录请求参数、错误日志、模块、接口、功能等辅助日志筛查的字段
 */
@Aspect
@Component
public class LogAspect {

    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    @Autowired
    private LogService logService;

    // 控制日志记录开关的配置项，默认为true
    @Value("${log.aop.enable:true}")
    private boolean logEnable;

    /**
     * 定义切点，拦截所有Controller层的方法
     */
    @Pointcut("execution(* com.z.**.controller.*.*(..))")
    public void logPointCut() {}

    /**
     * 环绕通知，在方法执行前后记录日志
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 如果日志记录功能关闭，直接执行目标方法并返回
        if (!logEnable) {
            return point.proceed();
        }

        // 创建日志对象
        Log log = new Log();
        
        // 获取当前请求
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 记录请求开始时间
        long startTime = System.currentTimeMillis();

        // 获取当前登录用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null && authentication.isAuthenticated() && !(authentication.getPrincipal() instanceof String)) {
            User user = (User) authentication.getPrincipal();
            log.setUserId(user.getId());
            log.setUsername(user.getUsername());
        }

        // 获取方法签名
        MethodSignature signature = (MethodSignature) point.getSignature();
        String className = signature.getDeclaringTypeName();
        String methodName = signature.getName();
        
        // 设置请求信息
        log.setApiPath(request.getRequestURI());
        log.setRequestMethod(request.getMethod());
        log.setRequestIp(getClientIp(request));
        log.setUserAgent(request.getHeader("User-Agent"));
        // 设置服务器IP
        log.setServerIp(getServerIp());
        
        // 设置模块信息
        String moduleName = getModuleName(className);
        log.setModule(moduleName);
        log.setOperation(getOperationDesc(className, methodName));

        // 设置请求参数
        Object[] args = point.getArgs();
        try {
            String params = JSONObject.toJSONString(args);
            log.setRequestParams(params);
        } catch (Exception e) {
            logger.error("参数解析失败: {}", e.getMessage());
            log.setRequestParams(Arrays.toString(args));
        }

        Object result = null;
        try {
            // 执行目标方法
            result = point.proceed();
            
            // 设置响应信息
            if (result != null) {
                try {
                    String resultStr = JSONObject.toJSONString(result);
                    if (resultStr.length() > 500) {
                        resultStr = resultStr.substring(0, 500) + "...";
                    }
                    log.setResponseMsg(resultStr);
                } catch (Exception e) {
                    log.setResponseMsg("响应结果解析失败");
                }
            }
            // 默认状态码为200
            log.setStatusCode(200);
        } catch (Throwable throwable) {
            // 记录异常信息
            log.setStatusCode(500);
            log.setErrorMsg(getExceptionMessage(throwable));
            logger.error("请求执行异常: {}", throwable.getMessage());
            // 重新抛出异常，不影响原有异常处理流程
            throw throwable;
        } finally {
            // 计算请求耗时
            long endTime = System.currentTimeMillis();
            log.setExecuteTime(endTime - startTime);
            
            // 异步保存日志
            logService.saveAsync(log);
        }

        return result;
    }

    /**
     * 获取服务器IP地址
     */
    private String getServerIp() {
        try {
            // 尝试获取本机所有网卡的IP地址
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
                while (inetAddresses.hasMoreElements()) {
                    InetAddress inetAddress = inetAddresses.nextElement();
                    // 排除回环地址和IPv6地址
                    if (!inetAddress.isLoopbackAddress() && inetAddress.getHostAddress().indexOf(':') == -1) {
                        return inetAddress.getHostAddress();
                    }
                }
            }
            // 如果没有找到非回环IPv4地址，返回默认值
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException | SocketException e) {
            logger.error("获取服务器IP地址失败: {}", e.getMessage());
            return "unknown";
        }
    }

    /**
     * 获取客户端真实IP地址
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 多级代理情况下，取第一个IP
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }
        return ip;
    }

    /**
     * 获取模块名称
     */
    private String getModuleName(String className) {
        // 从类名中提取模块名称，如UserController -> 用户管理
        String simpleName = className.substring(className.lastIndexOf(".") + 1);
        if (simpleName.endsWith("Controller")) {
            String module = simpleName.substring(0, simpleName.length() - "Controller".length());
            // 首字母小写处理
            return Character.toLowerCase(module.charAt(0)) + module.substring(1) + "管理";
        }
        return "未知模块";
    }

    /**
     * 获取操作描述
     */
    private String getOperationDesc(String className, String methodName) {
        // 简单的方法名称映射，实际项目中可以通过注解或配置文件配置更详细的描述
        String operation = "未知操作";
        if (methodName.startsWith("add") || methodName.startsWith("create")) {
            operation = "新增";
        } else if (methodName.startsWith("update")) {
            operation = "修改";
        } else if (methodName.startsWith("delete") || methodName.startsWith("remove")) {
            operation = "删除";
        } else if (methodName.startsWith("get") || methodName.startsWith("find") || methodName.startsWith("query")) {
            operation = "查询";
        } else if (methodName.startsWith("login")) {
            operation = "登录";
        } else if (methodName.startsWith("logout")) {
            operation = "登出";
        }
        return operation;
    }

    /**
     * 获取异常信息
     */
    private String getExceptionMessage(Throwable throwable) {
        StringBuilder message = new StringBuilder(throwable.getMessage());
        if (message.length() > 500) {
            return message.substring(0, 500) + "...";
        }
        return message.toString();
    }

    /**
     * 设置日志开关状态
     */
    public void setLogEnable(boolean enable) {
        this.logEnable = enable;
    }

    /**
     * 获取当前日志开关状态
     */
    public boolean isLogEnable() {
        return this.logEnable;
    }
}